import { useState, useEffect, useMemo, useCallback } from 'react';
import Taro from '@tarojs/taro';
import { View, Text, ScrollView, Button, Picker } from '@tarojs/components';
import { RemoteBluetooth, ConnectionState, EmitEvent, Operation, Device } from '@/utils';

import './index.css';

const useBluetooth = () => {
  const [logs, setLogs] = useState<string[]>([]);
  const [states, setStates] = useState<{
    deviceId?: string;
    connected: ConnectionState;
    services: Taro.getBLEDeviceServices.BLEService[];
    characteristics: Taro.getBLEDeviceCharacteristics.BLECharacteristic[];
    devices: Device[];
  }>({
    connected: ConnectionState.DISCONNECTED,
    services: [],
    characteristics: [],
    devices: []
  });

  const [receivedData, setReceivedData] = useState<string>('');

  const bluetooth = useMemo(() => {
    return new RemoteBluetooth({
      deviceNameFilter: /.*/,
      rssiThreshold: -80,
      splitterOptions: {
        chunkSize: 512
      }
    });
  }, []);

  const addLog = useCallback((log: string) => {
    setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()}: ${log}`]);
  }, []);

  const options = useMemo(() => {
    const asyncStates = () => {
      setStates((prev) => {
        return {
          ...prev,
          ...bluetooth.getState()
        };
      });
    };
    return {
      init: async () => {
        addLog('初始化蓝牙适配器...');
        try {
          const { authSetting } = await Taro.getSetting();
          if (!authSetting['scope.userLocation']) {
            await Taro.authorize({ scope: 'scope.userLocation' });
          }
          if (!authSetting['scope.userLocationAccuracy']) {
            await Taro.authorize({ scope: 'scope.userLocationAccuracy' });
          }
        } catch (error) {
          console.log('error', error);
        }
        await bluetooth.init();
        addLog('蓝牙适配器初始化成功');
        bluetooth
          .on(EmitEvent.deviceFound, (device) => {
            addLog(`发现设备: ${device.name || '未知'} (${device.deviceId})`);
            asyncStates();
          })
          .on(EmitEvent.connectionStateChange, ({ deviceId, connected }) => {
            const status = connected ? '已连接' : '已断开';
            addLog(`设备 ${deviceId} ${status}`);
            asyncStates();
          });
      },
      cancel: () => {
        bluetooth.disconnect();
        bluetooth.abortScan();
      },
      scanDevices: () => {
        addLog('开始扫描设备...');
        bluetooth.scanDevices({ timeout: 10000 }).then(() => {
          addLog('扫描完成');
        });
        asyncStates();
      },
      connectDevice: async (device: any) => {
        try {
          addLog(`正在连接 ${device.name || device.deviceId}...`);
          await bluetooth.connect(device.deviceId);
          asyncStates();
        } catch (err) {
          addLog(`连接失败: ${err.message}`);
        }
      },
      discoverCharacteristics: async (serviceId: string) => {
        try {
          addLog(`正在发现服务 ${serviceId} 的特征值...`);
          const chars = await bluetooth.discoverCharacteristics(serviceId);
          asyncStates();
          addLog(`发现 ${chars?.length || 0} 个特征值`);
        } catch (err) {
          addLog(`发现特征值失败: ${err.message}`);
        }
      },
      startNotification: async (serviceId: string, characteristicId: string) => {
        try {
          addLog(`正在启用通知: ${serviceId} / ${characteristicId}`);
          await bluetooth.startNotification(serviceId, characteristicId);
          addLog('通知已启用');
        } catch (err) {
          addLog(`启用通知失败: ${err.message}`);
        }
      },
      setConfig: (server?: string, ch?: string) => {
        bluetooth.configure(server, ch);
      },
      disconnect: () => {
        bluetooth.disconnect();
      },
      sendData: async (type: Operation, str?: string) => {
        try {
          switch (type) {
            case Operation.WRITE:
              addLog(`启动读`);
              try {
                const response = await bluetooth.readRemoteControllerVersionInfo();
                addLog(`读取数据: ${response}`);
                setReceivedData(response || '');
              } catch (error) {
                console.log('error', error);
              }

              break;
            default:
              break;
          }
        } catch (err) {
          addLog(`发送失败: ${err.message}`);
        }
      },
      asyncStates
    };
  }, [bluetooth, addLog]);

  return [{ logs, states, receivedData }, options] as const;
};

const Index: React.FC = () => {
  const [
    { logs, states, receivedData },
    { init, cancel, scanDevices, connectDevice, startNotification, discoverCharacteristics, setConfig, sendData }
  ] = useBluetooth();
  const [selectedService, setSelectedService] = useState('');
  const [selectedChar, setSelectedChar] = useState('');
  // 初始化
  useEffect(() => {
    init();
    return () => {
      cancel();
    };
  }, [cancel, init]);

  return (
    <View className="bluetooth-test">
      <View className="section">
        <Text className="title">蓝牙测试工具</Text>
        <Text>状态: {ConnectionState[states.connected]}</Text>
      </View>

      <View className="section">
        <Button onClick={scanDevices} disabled={states.connected !== ConnectionState.DISCONNECTED}>
          扫描设备1
        </Button>

        {states.devices.length > 0 && (
          <View className="device-list">
            <Text>发现设备 ({states.devices.length}):</Text>
            {states.devices.map((device) => (
              <View key={device.deviceId} className="device-item">
                <Text>
                  {device.name || '未知设备'} ({device.deviceId})
                </Text>
                <Button
                  size="mini"
                  onClick={() => connectDevice(device)}
                  disabled={states.connected !== ConnectionState.DISCONNECTED}
                >
                  连接
                </Button>
              </View>
            ))}
          </View>
        )}
      </View>

      {states.connected === ConnectionState.CONNECTED && (
        <>
          <View className="section">
            <Text>已连接设备: {states.deviceId}</Text>
            {/* onClick={disconnectDevice} */}
            <Button onClick={() => cancel()}>断开连接</Button>
          </View>

          <View className="section">
            <Text>服务列表 ({states.services.length}):</Text>
            <Picker
              mode="selector"
              range={states.services}
              rangeKey="uuid"
              onChange={(e) => {
                const service = states.services[e.detail.value];
                setSelectedService(service.uuid);
                discoverCharacteristics(service.uuid);

                setConfig(service.uuid);
              }}
            >
              <View className="picker">{selectedService || '选择服务'}</View>
            </Picker>

            {states.characteristics.length > 0 && (
              <>
                <Text>特征值列表 ({states.characteristics.length}):</Text>
                <Picker
                  mode="selector"
                  range={states.characteristics}
                  rangeKey="uuid"
                  onChange={(e) => {
                    const char = states.characteristics[e.detail.value];
                    setSelectedChar(char.uuid);
                    setConfig(selectedService, char.uuid);
                  }}
                >
                  <View className="picker">{selectedChar || '选择特征值'}</View>
                </Picker>

                <Button
                  onClick={() => startNotification(selectedService, selectedChar)}
                  disabled={!selectedService || !selectedChar}
                >
                  启用通知
                </Button>
              </>
            )}
          </View>

          <View className="section">
            <View className="button-group">
              <Button
                onClick={() => {
                  sendData(Operation.WRITE);
                }}
              >
                读取版本信息
              </Button>

              <Button disabled>写入版本信息</Button>
            </View>
          </View>

          <View className="section">
            <Text>接收到的数据:</Text>
            <Text> {receivedData ? hexStringToObject(receivedData).readableText : ''}</Text>
          </View>
        </>
      )}

      <View className="section">
        <Text>操作日志:</Text>
        <ScrollView scrollY className="log-box">
          {logs.map((log, i) => (
            <Text key={i}>{log}</Text>
          ))}
        </ScrollView>
      </View>
    </View>
  );
};
export default Index;

function hexStringToObject(hexStr) {
  // 1. 分割十六进制字符串
  const hexArray = hexStr.trim().split(' ').filter(Boolean);

  // 2. 转换控制字符
  const controlChars = {};
  const printable = [];

  hexArray.forEach((hex) => {
    const dec = parseInt(hex, 16);
    if (dec < 0x20 || dec === 0x7f) {
      // 控制字符处理
      controlChars[hex] = getControlCharName(dec);
    } else {
      // 可打印字符
      printable.push(String.fromCharCode(dec));
    }
  });

  // 3. 提取版本信息
  const fullText = printable.join('');
  const versionMatch = fullText.match(/[fF][wW]:([Vv]\d{2})/);
  const version = versionMatch ? versionMatch[1].toUpperCase() : null;

  // 4. 构建结果对象
  return {
    rawHex: hexStr,
    controlChars,
    readableText: fullText,
    version,
    isValid: version !== null,
    warnings: Object.keys(controlChars).length ? ['Contains control characters'] : []
  };
}

// 控制字符名称映射
function getControlCharName(code) {
  const names = {
    0x00: 'NULL',
    0x01: 'SOH',
    0x02: 'STX',
    0x03: 'ETX',
    0x04: 'EOT',
    0x05: 'ENQ',
    0x06: 'ACK',
    0x07: 'BEL',
    0x08: 'BS',
    0x09: 'HT',
    0x0a: 'LF',
    0x0b: 'VT',
    0x0c: 'FF',
    0x0d: 'CR',
    0x0e: 'SO',
    0x0f: 'SI',
    0x7f: 'DEL'
  };
  return names[code] || `Control Character 0x${code.toString(16).toUpperCase()}`;
}
